/*
    Invtro for Inércia Demoparty 2010

    http://creativecommons.org/licenses/by-nc-sa/2.5/
    
    Victor Martins
    www.pixelnerve.com
*/


class Particle
{
    Particle( int index, float timeToLive )
    {
        _index = index;
        reset( timeToLive );
    }


    Particle( int index, Vector3 emitter, float timeToLive )
    {
        _index = index;
        reset( emitter, timeToLive );
    }


    void reset( float timeToLive )
    {
        _age = 0;
        _timeToLive = timeToLive;
        _size = random( 1, 6 );
        _originSize = _size;
        _speed = random( 1, 6 );

        _isDead = false;

        if( _pos == null ) _pos = new Vector3( random(-300, 300), random(-0, 50), random(-500, 500) );
        else _pos.set( random(-300, 300), random(-300, 300), random(-300, 300) );
//        else _pos = _followPath.getPointOnPath( 0 );
        
        _oldPos = _pos.copy();
        _origin = _pos.copy();


        if( _vel == null ) _vel = new Vector3();
        else _vel.reset();

        _tailSize = 8;
        _tailRenderSegments = 0;
        if( _tailList == null ) _tailList = new ArrayList();
        else _tailList.clear();
        _tailList.add( _pos );
        for( int i=0; i<_tailSize; i++ )
        {
            _tailList.add( _pos.copy() );
            _tailRenderSegments++;
        }


        int rnd = (int)random(_colors.size());
        _color = ((Color4)_colors.get( rnd )).copy();
        _originColor = ((Color4)_colors.get( rnd )).copy();

        float radius = 5;
        float u = random(0, PI );
        float v = random(0, 2*PI );
	float x = sin(u) * cos(v);
	float y = sin(u) * sin(v);
	float z = cos(u);        
        if( _offset == null ) _offset = new Vector3( x*radius, y*radius, z*radius );
        _offset.set( x*radius, y*radius, z*radius );
        
        
        _vel.set( random(-1, 1), random(-1, 1), random(-1, 1) );
        _vel.mul( _speed * 0.02 );


        _startTime = timer.getCurrTime();
    }


    void reset( Vector3 pos, float timeToLive )
    {
        _age = 0;
        _timeToLive = timeToLive;
        _size = random( 1, 6 );
        _originSize = _size;
        _speed = random( 1, 6 );

        _isDead = false;

        _pos = pos.copy();
        // Add some offset to position
//        float off = 50;
//        _pos.add( new Vector3( random(-off, off), random(-off, off), random(-off, off)) );

        _oldPos = _pos.copy();
        _origin = _pos.copy();


        if( _vel == null ) _vel = new Vector3();
        else _vel.reset();

        _tailSize = 8;
        _tailRenderSegments = 0;
        if( _tailList == null ) _tailList = new ArrayList();
        else _tailList.clear();
        _tailList.add( _pos );
        for( int i=0; i<_tailSize; i++ )
        {
            _tailList.add( _pos.copy() );
            _tailRenderSegments++;
        }


        int rnd = (int)random(_colors.size());
        _color = ((Color4)_colors.get( rnd )).copy();
        _originColor = ((Color4)_colors.get( rnd )).copy();

/*        float radius = 0;
        float u = random(0, PI );
        float v = random(0, 2*PI );
	float x = sin(u) * cos(v);
	float y = sin(u) * sin(v);
	float z = cos(u);        
        if( _offset == null ) _offset = new Vector3( x*radius, y*radius, z*radius );
        _offset.set( x*radius, y*radius, z*radius );
        
        
        _vel.set( random(-1, 1), random(-1, 1), random(-1, 1) );
        _vel.mul( _speed * 0.02 );*/
        _vel.set( 0, 1, 0 );
        _vel.mul( _speed*0.2 );

        _startTime = timer.getCurrTime();
    }




    void update( float time )
    {
        float t = MathUtils.clamp( (time - _startTime), 0, 1 );

        _size = _originSize * t;

//        if(t < 1.0 )    _color = Color4.mul( _originColor, t );

        // fade out
        float timeToFade = 5.0;
        if( _age > (_timeToLive-timeToFade) )
            _color.a -= 1.0/ (60.0*timeToFade);


        _oldPos = _pos.copy();
        _pos.add( _vel );
//        _vel.mul( 0.995 );


        // Constraint to floor level
//        constraintToFloor( 0 );
        

        //
        // time to die
        //
        if( _age > _timeToLive )
        {
            _isDead = true;
        }


        //
        // Increase age
        //
        _age += (1.0/60.0f);
    }


/***
    void update( float time )
    {
        float t = MathUtils.clamp( (time - _startTime), 0, 1 );

        _size = _originSize * t;

        if(t < 1.0 )
            _color = Color4.mul( _originColor, t );

        Vector3 tmp = _followPath.getPointOnPath( (time-_startTime)*_speed );
        if( tmp != null )
        {
            _vel = Vector3.sub( _oldPos, _pos );
            _vel.normalize();
            _vel.mul( _speed );

            _oldPos = _pos.copy();
            _pos.set( tmp );


            Vector3 offTmp = _offset.copy();
            offTmp.mul( t );
            _pos.add( offTmp );


            Vector3 noi = new Vector3();
            noi.x = 2*noise( time*0.1, _pos.x*0.01, time*0.1+_index ) - 1;
            noi.y = 2*noise( time*0.01, _pos.y*0.01, time*0.1+_index ) - 1;
            noi.z = 2*noise( time*0.1, _pos.z*0.01, time*0.1+_index ) - 1;
            noi.mul( _speed*55, _speed*15, _speed*55 );
            _pos.add( noi );

            // Constraint to floor level
            constraintToFloor( 0 );
            
//            _vel.mul( noi );

//            float girth = _vel.length();
            float girth = _speed * 3;
            Vector3 head = ((Vector3)_tailList.get(0));
            head.set( _pos );
            for( int i=1; i<_tailSize; i++ )
            { 
                Vector3 curr = ((Vector3)_tailList.get(i));
                Vector3 prev = ((Vector3)_tailList.get(i-1));
                float dx = curr.x - prev.x;
                float dy = curr.y - prev.y;
                float dz = curr.z - prev.z;
                float d = sqrt( dx*dx + dy*dy + dz*dz );
                float invD = 1.0 / d;
                curr.x = (prev.x + ((dx * girth) * invD));
                curr.y = (prev.y + ((dy * girth) * invD));
                curr.z = (prev.z + ((dz * girth) * invD));                 
            }
        }
        else
        {
            _isDead = true;
        }


        //
        // time to die
        //
        if( _age > _timeToLive )
        {
            _isDead = true;
        }


        //
        // Increase age
        //
        _age += (1.0/60.0f);
    }
***/


    boolean isDead()
    {
        return _isDead;
    }
    
    
    void constraintToFloor( float height )
    {
        if( _pos.y < height ) _pos.y = height;
    }
    
    

    //
    // Members
    //

    int _index;

    float _startTime;

    float _speed;


    boolean _isDead;
    float _age;
    float _timeToLive;

    float _size;
    float _originSize;

    Vector3 _offset;
    Vector3 _origin, _oldPos, _pos;
    Vector3 _vel;

    int  _tailRenderSegments;    // counts number of tail segments to render  
    int  _tailSize; 
    ArrayList _tailList; 
  
    Color4 _color;
    Color4 _originColor;
}
    
